package cn.pconline.autoclub.task;

import cn.pc.util.JsonClient;
import cn.pc.util.JsonResult;
import cn.pconline.autoclub.task.util.PcHttpUtils;
import cn.pconline.r.client.SimpleHttpTemplate;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 发系统消息和发车友会动态消息的定时任务 发系统消息可配置频率低点，动态消息可高点
 *
 * @author guoqiang,chensy
 */
public class SendMsgTask {

    private static Logger log = LoggerFactory.getLogger(SendMsgTask.class);

    public static void setLog(Logger log) {
        SendMsgTask.log = log;
    }
    private static String firstMsgTask = " select message_id,content,less_num,status,create_by,type from ac_message where now()>=send_at and status = ? and type = ?";
    private static String secondMsgTask = " select message_id,content,less_num,status,create_by,type from ac_message where status = ? and type = ?";
    private static String sendMsgTask = " select message_id,content,less_num,status,create_by,type from ac_message where message_id = ? and type = ?";
    private static String updateTaskStatus = " update ac_message set status = ? WHERE message_id = ? ";
    private static String editTaskEnd = " update ac_message set less_num = ? WHERE message_id = ? ";
    private static String listSendMsg = " select message_detail_id,user_id,status from ac_message_detail where message_id=? and status =? ";
    private static String editSendMsg = " update ac_message_detail set status=?,send_at=? where message_detail_id=? ";

    private String getMsgFeedUrl() {
        return FileUtils.getConfig("msgFeedUrl");
    }

    private int getSysNoticeTypeId() {
        String typeId = FileUtils.getConfig("sysNoticeTpyeId");
        if (typeId != null) {
            return Integer.valueOf(typeId);
        }
        return 0;
    }

    private int getClubDynaNoticeTypeId() {
        String typeId = FileUtils.getConfig("clubDynaNoticeTpyeId");
        if (typeId != null) {
            return Integer.valueOf(typeId);
        }
        return 0;
    }

    /**
     * 查询消息列表
     *
     * @param sql
     * @param status
     * @return
     * @throws SQLException
     */
    private List<Message> getMsgList(String sql, int status, int type) throws SQLException {
        Connection conn = DBUtils.getConnection();
        PreparedStatement ps;
        ResultSet rs;
        List<Message> list = new ArrayList<Message>();
        ps = conn.prepareStatement(sql);
        ps.setInt(1, status);
        ps.setInt(2, type);
        rs = ps.executeQuery();
        while (rs.next()) {
            Message msg = new Message();
            msg.setMessageId(rs.getLong("message_id"));
            msg.setContent(rs.getString("content"));
            msg.setLessNum(rs.getInt("less_num"));
            msg.setStatus(rs.getInt("status"));
            msg.setCreateBy(rs.getLong("create_by"));
            msg.setType(rs.getInt("type"));
            list.add(msg);
        }
        DBUtils.releaseConn(conn, ps, rs);
        return list;
    }

    /**
     * 发送所有消息
     *
     * @throws SQLException
     */
    public void sendAllMsg(int type) throws SQLException {
        //取出需要重发的列表
        List<Message> listBack = getMsgList(secondMsgTask, Message.STATUS_BACK, type);
        sendMessageList(listBack);
        List<Message> listFirstSend = getMsgList(firstMsgTask, Message.STATUS_SETOUT, type);
        //取出首次发送的列表
        sendMessageList(listFirstSend);
        log.info(String.format("%s msg task has been send !", listBack.size() + listFirstSend.size()));
    }

    /**
     * 发送某一消息
     *
     * @param messageId
     * @throws SQLException
     */
    public void sendOneMsg(int messageId, int type) throws SQLException {
        //取出需要重发的列表
        List<Message> message = getMsgList(sendMsgTask, messageId, type);
        sendMessageList(message);
    }

    public static void main(String[] args) throws SQLException {
        AppUtils.initLog(SendMsgTask.class);
        if (args == null || args.length == 0) {
            System.out.println("please input[sendSysMsg [msgId]| sendDynaMsg [msgId]]");
            return;
        }
        int type;
        int msgId = 0;
        if (args.length == 2) {
            msgId = Integer.parseInt(args[1]);
        }
        if ("sendSysMsg".equals(args[0])) {
            type = Message.TYPE_SYS;
        } else if ("sendDynaMsg".equals(args[0])) {
            type = Message.TYPE_CLUB_DYNA;
        } else {
            System.out.println("input error!");
            return;
        }
        SendMsgTask task = new SendMsgTask();
        if (msgId == 0) {
            task.sendAllMsg(type);
        } else {
            task.sendOneMsg(msgId, type);
        }
    }

    private Map<String, Object> jsonToMap(String jsonStr) {
        JSONObject obj;
        try {
            obj = JSONObject.parseObject(jsonStr);
        } catch (JSONException e) {
            return new HashMap<String, Object>();
        }
        HashMap<String, Object> m = new HashMap<String, Object>();
        for (String k : obj.keySet()) {
            m.put(k, obj.get(k));
        }
        return m;
    }

    /**
     * 根据任务list发送消息（一次性全部发送）
     *
     * @param messageList
     * @throws SQLException
     */
    private void sendMessageList(List<Message> messageList) throws SQLException {
        String url = getMsgFeedUrl();
        int sysNoticeTypeId = getSysNoticeTypeId();
        int clubDynaNoticeTypeId = getClubDynaNoticeTypeId();
        if ("".equals(url) || url == null) {
            log.warn("url is null!");
            return;
        }
        if (sysNoticeTypeId == 0) {
            log.warn("sysNoticeTypeId is 0!");
            return;
        }
        if (clubDynaNoticeTypeId == 0) {
            log.warn("clubDynaNoticeTypeId is 0!");
            return;
        }
        Connection conn = DBUtils.getConnection();
        boolean oldCommit = DBUtils.getAutoCommitValue(conn);
        conn.setAutoCommit(false);
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            //组装R系统参数
            JsonClient jsonClient = new JsonClient();
            jsonClient.setDirectToBIP(false);
            SimpleHttpTemplate simpleHttpTemplate = PcHttpUtils.getSimpleHttpTemplate();
            jsonClient.setSimpleHttpTemplate(simpleHttpTemplate);

            //循环发送任务
            for (Message task : messageList) {
                log.info("be ready for sending msg");
                log.info("----msg[{}] :{}", task.getMessageId(), task.getContent());
                //重发取发送失败信息，首次发送取未发送消息
                int status = Message.SEND_FALSE;
                if (task.getStatus() == Message.STATUS_SETOUT) {
                    status = Message.SEND_SETOUT;
                }
                //根据任务ID取出未发送列表
                List<Message> sendRecords = new ArrayList<Message>();
                ps = conn.prepareStatement(listSendMsg);
                ps.setLong(1, task.getMessageId());
                ps.setLong(2, status);
                rs = ps.executeQuery();
                while (rs.next()) {
                    Message msg = new Message();
                    msg.setMessageDeatailId(rs.getLong("message_detail_id"));
                    msg.setUserId(rs.getLong("user_id"));
                    msg.setStatus(rs.getInt("status"));
                    sendRecords.add(msg);
                }
                rs.close();
                ps.close();

                int countSuccess = 0;
                //发送消息
                if (sendRecords == null || sendRecords.isEmpty()) {
                    log.error("can't find any record!! {},{},{}", listSendMsg, task.getMessageId(), status);
                } else {
                    //将任务状态改成发送中
                    ps = conn.prepareStatement(updateTaskStatus);
                    ps.setLong(1, Message.STATUS_SEND);
                    ps.setLong(2, task.getMessageId());
                    ps.executeUpdate();
                    ps.close();

                    List<Message> sends = new ArrayList<Message>();
                    int sendOk = 0;
                    for (int i = 0; i < sendRecords.size(); i++) {
                        Message message = sendRecords.get(i);
                        message.setTime(DateUtils.getNow());

                        JsonResult jsonResult;
                        if (task.getType() == Message.TYPE_SYS) {
                            Map<String, Object> contents = new HashMap<String, Object>(2);
                            contents.put("content", task.getContent());
                            jsonResult = jsonClient.sysnotice(url, 0, message.getUserId(), sysNoticeTypeId, contents);
                        } else if (task.getType() == Message.TYPE_CLUB_DYNA) {
                            jsonResult = jsonClient.sysnotice(url, task.getCreateBy(), message.getUserId(), clubDynaNoticeTypeId, jsonToMap(task.getContent()));
                        } else {
                            log.error("wrong ac_message.type[{}] value({})", task.getMessageId(), task.getType());
                            continue;
                        }
                        if (jsonResult.getCode() == 0) {
                            sendOk++;
                            message.setStatus(Message.SEND_OK);
                        } else {
                            message.setStatus(Message.SEND_FALSE);
                        }
                        sends.add(message);
                        //成功发送500条数据更新数据库，或者最后一条发送后更新数据库
                        if (sendOk % 500 == 0 || i == sendRecords.size() - 1) {
                            ps = conn.prepareStatement(editSendMsg);
                            for (Message send : sends) {
                                if (send.getStatus() == Message.SEND_OK) {
                                    String sql = String.format("delete from ac_message_detail where message_detail_id=%s", send.getMessageDeatailId());
                                    ps.addBatch(sql);
                                } else {
                                    ps.setInt(1, send.getStatus());
                                    ps.setString(2, DateUtils.format(send.getTime(), "yyyy-MM-dd HH:mm:ss"));
                                    ps.setLong(3, send.getMessageDeatailId());
                                    ps.addBatch();
                                }
                            }
                            ps.executeBatch();
                            ps.close();
                            //更新剩余的数量
                            ps = conn.prepareStatement(editTaskEnd);
                            int lessNum = task.getLessNum() - sendOk;
                            if (lessNum < 0) {
                                lessNum = 0;
                            }
                            task.setLessNum(lessNum);
                            ps.setInt(1, task.getLessNum());
                            ps.setLong(2, task.getMessageId());
                            ps.executeUpdate();
                            ps.close();
                            countSuccess += sendOk;
                            log.info("{} msg record has sent success!", sendOk);
                            //初始化已发送列表和发送成功计数
                            sends = new ArrayList<Message>();
                            sendOk = 0;
                        }
                    }
                    // 发送结束，修改任务状态
                    ps = conn.prepareStatement(updateTaskStatus);
                    ps.setInt(1, Message.STATUS_END);
                    ps.setLong(2, task.getMessageId());
                    ps.executeUpdate();
                    ps.close();
                    conn.commit();
                    log.info("all msg({}) record has sent! {} success!", sendRecords.size(), countSuccess);
                    log.info("one msg send done!!!");
                    //发一条消息提交一次，不清MC 查询的地方没有用到缓存
                }
            }
        } catch (Exception e) {
            log.error("sendMessageList exception", e);
            try {
                conn.rollback();
            } catch (SQLException e1) {
                log.error("sendMessageList rollback exception", e1);
            }
        } finally {
            conn.setAutoCommit(oldCommit);
            DBUtils.releaseConn(conn, ps, rs);
        }
    }
}
